package com.example.myspringframework.beans.factory.support;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.example.myspringframework.beans.BeansException;
import com.example.myspringframework.beans.factory.ConfigurableBeanFactory;
import com.example.myspringframework.beans.factory.FactoryBean;
import com.example.myspringframework.beans.factory.config.BeanDefinition;
import com.example.myspringframework.beans.factory.config.BeanPostProcessor;
import com.example.myspringframework.core.convert.ConversionService;
import com.example.myspringframework.utils.StringValueResolver;

/**
 * 主要实现了getBean的功能
 * 继承了DefaultSingletonBeanRegistry,说明该类拥有了添加和获取单例bean的功能
 * 实现ConfigurableBeanFactory接口，实现具体的扩展BeanFactory的能力
 */
public abstract class  AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {
    /**
     * 存储所有的BeanPostProcessor
     */
    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<>();
    /**
     * 存储FactoryBean中的单例bean
     */
    private final Map<String, Object> factoryBeanObjectCache = new HashMap<>();
    /**
     * 存储所有的字符解析器
     */
    private final List<StringValueResolver> embeddedValueResolvers = new ArrayList<StringValueResolver>();

    /**
     * 类型转换器
     */
    private ConversionService conversionService;

    /**
     * 根据beanName获取一个bean
     */
    @Override
    public Object getBean(String beanName) throws BeansException {
        // 先从单例bean的容器中查找
        Object bean = this.getSingleton(beanName);
        if (bean != null) {
            //如果是FactoryBean，从FactoryBean#getObject中创建bean
            return this.getObjectForBeanInstance(bean, beanName);
        }
        // 单例bean不存在就创建一个
        BeanDefinition beanDefinition = this.getBeanDefinition(beanName);
        bean = this.createBean(beanName, beanDefinition);
        return this.getObjectForBeanInstance(bean, beanName);
    }

    @Override
    public <T> T getBean(String beanName, Class<T> requiredType) throws BeansException {
        return (T)this.getBean(beanName);
    }

    @Override
    public boolean containsBean(String beanName) {
        return this.containsBeanDefinition(beanName);
    }
    protected abstract boolean containsBeanDefinition(String beanName);

    /**
     * 用于实现FactoryBean功能，如果是FactoryBean，从FactoryBean#getObject中创建bean
     */
    protected Object getObjectForBeanInstance(Object beanInstance, String beanName) {
        Object object = beanInstance;
        if (beanInstance instanceof FactoryBean<?> factoryBean) {
            try {
                if (factoryBean.isSingleton()) {
                    object = this.factoryBeanObjectCache.get(beanName);
                    if (object == null) {
                        object = factoryBean.getObject();
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                } else {
                    object = factoryBean.getObject();
                }
            } catch (Exception e) {
                throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", e);
            }
        }
        return object;
    }

    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    /**
     * 创建bean的具体方法，交给子类去实现
     */
    protected abstract Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException;

    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        this.beanPostProcessors.remove(beanPostProcessor);
        this.beanPostProcessors.add(beanPostProcessor);
    }

    @Override
    public List<BeanPostProcessor> getBeanPostProcessors() {
        return this.beanPostProcessors;
    }

    /**
     * 添加字符解析器
     */
    public void addEmbeddedValueResolver(StringValueResolver valueResolver) {
        this.embeddedValueResolvers.add(valueResolver);
    }

    /**
     * 使用字符解析器
     */
    @Override
    public String resolveEmbeddedValue(String value) {
        String result = value;
        for (StringValueResolver resolver : this.embeddedValueResolvers) {
            result = resolver.resolveStringValue(result);
        }
        return result;
    }

    /**
     * 获取类型转换器
     */
    @Override
    public ConversionService getConversionService() {
        return conversionService;
    }

    /**
     * 设置类型转换器
     */
    @Override
    public void setConversionService(ConversionService conversionService) {
        this.conversionService = conversionService;
    }
}
